package com.xiangxiao.rpan.gateway.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.xiangxiao.rpan.gateway.Application;
import org.springframework.beans.factory.annotation.Value;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @auther xiangxiao
 * @email 573768011@qq.com
 * @data 2023/2/13 19:11
 */
@Component
public class ErrorFilter extends ZuulFilter {
  private static Logger logger = LoggerFactory.getLogger(Application.class);

  private static final String FILTER_TYPE = "filter_type";

  private static final String ERROR_STATUS_CODE_KEY = "error.status_code";
  public static final String DEFAULT_ERR_MSG = "系统繁忙,请稍后再试";

  protected static final String SEND_ERROR_FILTER_RAN = "sendErrorFilter.ran";

  @Value("${server.error.path:/error}")
  private String errorPath;

  public ErrorFilter(){
    System.out.println("初始化errorfilter");
  }

  @Override
  public String filterType() {
    return "error";
  }

  @Override
  public int filterOrder() {
    return 1;
  }

  @Override
  public boolean shouldFilter() {
    boolean res=true;
    RequestContext ctx = RequestContext.getCurrentContext();
    Throwable throwable = ctx.getThrowable();
    res = (throwable != null);
    return res;
  }

  @Override
  public Object run() {
    logger.warn(" --- 网关路由服务出现连接服务不成功，进入errorfilter处理-----");

    try {
      RequestContext ctx = RequestContext.getCurrentContext();
      ZuulException exception = findZuulException(ctx.getThrowable());
      HttpServletRequest request = ctx.getRequest();
      request.setAttribute("javax.servlet.error.status_code", exception.nStatusCode);
      //request.setAttribute("javax.servlet.error.message", "");

      logger.warn("getRequestURI:{} , msg:", ctx.getRequest().getRequestURI(),exception);

      if (StringUtils.hasText(exception.errorCause)) {
        request.setAttribute("javax.servlet.error.message", exception.errorCause);
      }

      RequestDispatcher dispatcher = request.getRequestDispatcher(
          this.errorPath);
      if (dispatcher != null) {
        ctx.set(SEND_ERROR_FILTER_RAN, true);
        //返回的RequestContext类型变量ctx增加一个filter_type字段，说明是哪个filter
        ctx.set(FILTER_TYPE, "ErrorFilter");
        if (!ctx.getResponse().isCommitted()) {
          dispatcher.forward(request, ctx.getResponse());
        }
      }
    }
    catch (Exception ex) {
      ReflectionUtils.rethrowRuntimeException(ex);
    }
    return null;

  }

  ZuulException findZuulException(Throwable throwable) {
    if (throwable.getCause() instanceof ZuulRuntimeException) {
      // this was a failure initiated by one of the local filters
      return (ZuulException) throwable.getCause().getCause();
    }

    if (ZuulException.class.isInstance(throwable.getCause())) {
      // wrapped zuul exception
      return (ZuulException) throwable.getCause();
    }

    if (throwable instanceof ZuulException) {
      // exception thrown by zuul lifecycle
      return (ZuulException) throwable;
    }

    // fallback, should never get here
    return new ZuulException(throwable, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null);
  }
}
